/**
 * 
 */

package com.chengyu.eyc.utils;

import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import lombok.extern.slf4j.Slf4j;

/**
 * @author kevin
 *
 */
@Slf4j
public final class AESUtil {

    // 加密方式
    private static String keyAlgorithm = "AES";

    // 避免重复new生成多个BouncyCastleProvider对象，因为GC回收不了，会造成内存溢出
    // 只在第一次调用decrypt()方法时才new 对象
    private static boolean initialized;

    // 生成iv
    private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException {
        AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm);
        params.init(new IvParameterSpec(iv));
        return params;
    }

    /** BouncyCastle作为安全提供，防止我们加密解密时候因为jdk内置的不支持改模式运行报错。 **/
    private static void initialize() {
        if (initialized) {
            return;
        }
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    public static void main(String[] args) {
        AESUtil aes = new AESUtil(
            "/uM6H5Neq19PbndSoHEgtyU3AMQvWxbImz8N9iL+n8/MHuNMFVPXQvEbQv16eg1tn4DR5OrcBg9POEsn6YC0Q5QlUMzU9mYFBkwqLhVWh6bEKQI4b1G8i8VHGQbZVYS6uwEqqQC9lBCLeTU415baFZBnXh8GaL8aU7PfFCSe7WHR57fCGlGwe5FbYMwmJZ8Ddx29Ce4lwO5q0hLMDYLeCsworXWqD4ZU4LD/wCp2/XyZdBVWXgZUMPaGF3pPEYTRbr9LrDw5ZoptepM6dlenHK+yAI80+eWgeUAOHiLuQLL7bLOv165b3MW5mHEgUmZ17DQ6JzunuEjqM7yogX3AJGOOu5Kb+6WNXxAQPUFmpF2OCQlCMJy95S+OyjauO0Cy7p1A1rBFnzU6/lv4p6qWUbbe2xSu9mu7E7OWnXIXLi4=",
            "Px9JnismMDf0km/S0AGkvQ==", "GzqYo/1IoqxmKo5YuMgULw==");
        log.info(aes.decrypt());
    }

    // 用于Base64解密
    private Base64.Decoder decoder = Base64.getDecoder();

    // 待解密的数据
    private String originalContent;

    // 会话密钥sessionKey
    private String encryptKey;

    // 加密算法的初始向量
    private String iv;

    public AESUtil(String originalContent, String encryptKey, String iv) {
        this.originalContent = originalContent;
        this.encryptKey = encryptKey;
        this.iv = iv;
        log.info("originalContent：{}",originalContent);
        log.info("key：{}",encryptKey);
        log.info("iv：{}",originalContent);
    }

    /**
     * AES解密 填充模式AES/CBC/PKCS7Padding 解密模式128
     *
     * @return 解密后的信息对象
     */
    public String decrypt() {
        initialize();
        try {
            // 数据填充方式
            // Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS7Padding”,”BC”);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm);
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv)));
            byte[] data = cipher.doFinal(decoder.decode(this.originalContent));
            return new String(data, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

}
